package com.sun.dream.fish.mvc;

import com.sun.dream.fish.session.DsfThreadLocalHelper;
import com.sun.dream.fish.util.HttpUtil;
import com.sun.dream.fish.vo.ResultVO;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.Objects;

/**
 * Description:
 * Created By ljl on 2023/12/05.
 */
@Component
@Aspect
@Slf4j
@Order(-1)
public class DsfAspect {
    private static final String POINT_CUT_REQUEST = "@annotation(org.springframework.web.bind.annotation.RequestMapping)";
    private static final String POINT_CUT_GET = "@annotation(org.springframework.web.bind.annotation.GetMapping)";
    private static final String POINT_CUT_POST = "@annotation(org.springframework.web.bind.annotation.PostMapping)";
    private static final String POINT_CUT_DELETE = "@annotation(org.springframework.web.bind.annotation.DeleteMapping)";
    private static final String POINT_CUT_PUT = "@annotation(org.springframework.web.bind.annotation.PutMapping)";

    public DsfAspect() {
    }

    @Pointcut(POINT_CUT_DELETE)
    public void executePointCutDelete() {
    }

    @Pointcut(POINT_CUT_POST)
    public void executePointCutPost() {
    }

    @Pointcut(POINT_CUT_REQUEST)
    public void executePointCutRequest() {
    }

    @Pointcut(POINT_CUT_GET)
    public void executePointCutGet() {
    }

    @Pointcut(POINT_CUT_PUT)
    public void executePointCutPut() {
    }

    @Around("executePointCutRequest()")
    public Object innerRequest(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        return this.innerDone(proceedingJoinPoint);
    }

    @Around("executePointCutDelete()")
    public Object innerDelete(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        return this.innerDone(proceedingJoinPoint);
    }

    @Around("executePointCutGet()")
    public Object innerGet(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        return this.innerDone(proceedingJoinPoint);
    }

    @Around("executePointCutPost()")
    public Object innerPost(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        return this.innerDone(proceedingJoinPoint);
    }

    @Around("executePointCutPut()")
    public Object innerPut(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        return this.innerDone(proceedingJoinPoint);
    }

    private Object innerDone(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start(proceedingJoinPoint.toShortString());
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        Objects.requireNonNull(requestAttributes, "请问这个requestAttributes去哪里了?");
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference("request");
        Objects.requireNonNull(request, "你是逗逼吗?HttpServletRequest啦?");
        DsfThreadLocalHelper.getDSFSession().setLocale(HttpUtil.getHeader(request, "Accept-language", "zh-CN"));
        boolean debugLog = false;
        if (!HttpMethod.HEAD.matches(request.getMethod()) && !ignore(request.getRequestURI())) {
            debugLog = true;
            //todo  实现查询系统用户业务
        }
        Object proceed;
        try {
            proceed = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        } catch (Exception ex) {
            if (ex instanceof UnauthorizedException) {
                return new ResultVO<>(null, 403);
            } else if (ex instanceof UnauthenticatedException) {
                return new ResultVO<>(null, 1000);
            }
            throw ex;
        } finally {
            DsfThreadLocalHelper.clear();
            stopWatch.stop();
            if (debugLog && log.isDebugEnabled()) {
                log.debug(stopWatch.prettyPrint());
            }
        }
        return proceed;
    }

    private boolean ignore(String requestURI) {
        //todo  实现过滤请求
        return false;
    }
}
